// Copyright (c) 2025 The Chromium Embedded Framework Authors. All rights
// reserved. Use of this source code is governed by a BSD-style license that can
// be found in the LICENSE file.

#include "cef/libcef/browser/setting_helper.h"

#include "cef/include/cef_request_context.h"
#include "cef/libcef/browser/thread_util.h"
#include "components/content_settings/core/browser/host_content_settings_map.h"
#include "url/gurl.h"

namespace setting_helper {

class RegistrationImpl final : public Registration, public CefRegistration {
 public:
  RegistrationImpl(Registrar* registrar, CefRefPtr<CefSettingObserver> observer)
      : registrar_(registrar), observer_(observer) {
    DCHECK(registrar_);
    DCHECK(observer_);
  }

  RegistrationImpl(const RegistrationImpl&) = delete;
  RegistrationImpl& operator=(const RegistrationImpl&) = delete;

  ~RegistrationImpl() override {
    CEF_REQUIRE_UIT();
    if (registrar_) {
      registrar_->RemoveObserver(this);
    }
  }

  void Detach() override {
    registrar_ = nullptr;
    observer_ = nullptr;
  }

  void RunCallback(const CefString& requesting_url,
                   const CefString& top_level_url,
                   cef_content_setting_types_t content_type) const override {
    observer_->OnSettingChanged(requesting_url, top_level_url, content_type);
  }

 private:
  raw_ptr<Registrar> registrar_;
  CefRefPtr<CefSettingObserver> observer_;

  IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(RegistrationImpl);
};

Registrar::~Registrar() {
  RemoveAll();
}

void Registrar::Init(HostContentSettingsMap* settings) {
  DCHECK(settings);
  DCHECK(IsEmpty() || settings_ == settings);
  settings_ = settings;
}

void Registrar::Reset() {
  RemoveAll();
  settings_ = nullptr;
}

void Registrar::RemoveAll() {
  if (!observers_.empty()) {
    settings_->RemoveObserver(this);
    for (auto& registration : observers_) {
      registration.Detach();
    }
    observers_.Clear();
  }
}

bool Registrar::IsEmpty() const {
  return observers_.empty();
}

CefRefPtr<CefRegistration> Registrar::AddObserver(
    CefRefPtr<CefSettingObserver> observer) {
  CHECK(settings_);

  RegistrationImpl* impl = new RegistrationImpl(this, observer);

  if (observers_.empty()) {
    settings_->AddObserver(this);
  }
  observers_.AddObserver(impl);

  return impl;
}

void Registrar::RemoveObserver(Registration* registration) {
  CHECK(settings_);

  observers_.RemoveObserver(registration);
  if (observers_.empty()) {
    settings_->RemoveObserver(this);
  }
}

void Registrar::OnContentSettingChanged(
    const ContentSettingsPattern& primary_pattern,
    const ContentSettingsPattern& secondary_pattern,
    ContentSettingsTypeSet content_type_set) {
  DCHECK(!IsEmpty());

  const CefString requesting_url(primary_pattern.ToRepresentativeUrl().spec());
  const CefString top_level_url(secondary_pattern.ToRepresentativeUrl().spec());
  const auto content_type = ToCefType(content_type_set.GetType());

  for (Registration& registration : observers_) {
    registration.RunCallback(requesting_url, top_level_url, content_type);
  }
}

#define TO_CEF_TYPE(name)         \
  case ContentSettingsType::name: \
    return CEF_CONTENT_SETTING_TYPE_##name

cef_content_setting_types_t ToCefType(ContentSettingsType type) {
  switch (type) {
    TO_CEF_TYPE(COOKIES);
    TO_CEF_TYPE(IMAGES);
    TO_CEF_TYPE(JAVASCRIPT);
    TO_CEF_TYPE(POPUPS);
    TO_CEF_TYPE(GEOLOCATION);
    TO_CEF_TYPE(NOTIFICATIONS);
    TO_CEF_TYPE(AUTO_SELECT_CERTIFICATE);
    TO_CEF_TYPE(MIXEDSCRIPT);
    TO_CEF_TYPE(MEDIASTREAM_MIC);
    TO_CEF_TYPE(MEDIASTREAM_CAMERA);
    TO_CEF_TYPE(PROTOCOL_HANDLERS);
    TO_CEF_TYPE(DEPRECATED_PPAPI_BROKER);
    TO_CEF_TYPE(AUTOMATIC_DOWNLOADS);
    TO_CEF_TYPE(MIDI_SYSEX);
    TO_CEF_TYPE(SSL_CERT_DECISIONS);
    TO_CEF_TYPE(PROTECTED_MEDIA_IDENTIFIER);
    TO_CEF_TYPE(APP_BANNER);
    TO_CEF_TYPE(SITE_ENGAGEMENT);
    TO_CEF_TYPE(DURABLE_STORAGE);
    TO_CEF_TYPE(USB_CHOOSER_DATA);
    TO_CEF_TYPE(BLUETOOTH_GUARD);
    TO_CEF_TYPE(BACKGROUND_SYNC);
    TO_CEF_TYPE(AUTOPLAY);
    TO_CEF_TYPE(IMPORTANT_SITE_INFO);
    TO_CEF_TYPE(PERMISSION_AUTOBLOCKER_DATA);
    TO_CEF_TYPE(ADS);
    TO_CEF_TYPE(ADS_DATA);
    TO_CEF_TYPE(MIDI);
    TO_CEF_TYPE(PASSWORD_PROTECTION);
    TO_CEF_TYPE(MEDIA_ENGAGEMENT);
    TO_CEF_TYPE(SOUND);
    TO_CEF_TYPE(CLIENT_HINTS);
    TO_CEF_TYPE(SENSORS);
    TO_CEF_TYPE(DEPRECATED_ACCESSIBILITY_EVENTS);
    TO_CEF_TYPE(PAYMENT_HANDLER);
    TO_CEF_TYPE(USB_GUARD);
    TO_CEF_TYPE(BACKGROUND_FETCH);
    TO_CEF_TYPE(INTENT_PICKER_DISPLAY);
    TO_CEF_TYPE(IDLE_DETECTION);
    TO_CEF_TYPE(SERIAL_GUARD);
    TO_CEF_TYPE(SERIAL_CHOOSER_DATA);
    TO_CEF_TYPE(PERIODIC_BACKGROUND_SYNC);
    TO_CEF_TYPE(BLUETOOTH_SCANNING);
    TO_CEF_TYPE(HID_GUARD);
    TO_CEF_TYPE(HID_CHOOSER_DATA);
    TO_CEF_TYPE(WAKE_LOCK_SCREEN);
    TO_CEF_TYPE(WAKE_LOCK_SYSTEM);
    TO_CEF_TYPE(LEGACY_COOKIE_ACCESS);
    TO_CEF_TYPE(FILE_SYSTEM_WRITE_GUARD);
    TO_CEF_TYPE(NFC);
    TO_CEF_TYPE(BLUETOOTH_CHOOSER_DATA);
    TO_CEF_TYPE(CLIPBOARD_READ_WRITE);
    TO_CEF_TYPE(CLIPBOARD_SANITIZED_WRITE);
    TO_CEF_TYPE(SAFE_BROWSING_URL_CHECK_DATA);
    TO_CEF_TYPE(VR);
    TO_CEF_TYPE(AR);
    TO_CEF_TYPE(FILE_SYSTEM_READ_GUARD);
    TO_CEF_TYPE(STORAGE_ACCESS);
    TO_CEF_TYPE(CAMERA_PAN_TILT_ZOOM);
    TO_CEF_TYPE(WINDOW_MANAGEMENT);
    TO_CEF_TYPE(LOCAL_FONTS);
    TO_CEF_TYPE(PERMISSION_AUTOREVOCATION_DATA);
    TO_CEF_TYPE(FILE_SYSTEM_LAST_PICKED_DIRECTORY);
    TO_CEF_TYPE(DISPLAY_CAPTURE);
    TO_CEF_TYPE(FILE_SYSTEM_ACCESS_CHOOSER_DATA);
    TO_CEF_TYPE(FEDERATED_IDENTITY_SHARING);
    TO_CEF_TYPE(JAVASCRIPT_JIT);
    TO_CEF_TYPE(HTTP_ALLOWED);
    TO_CEF_TYPE(FORMFILL_METADATA);
    TO_CEF_TYPE(DEPRECATED_FEDERATED_IDENTITY_ACTIVE_SESSION);
    TO_CEF_TYPE(AUTO_DARK_WEB_CONTENT);
    TO_CEF_TYPE(REQUEST_DESKTOP_SITE);
    TO_CEF_TYPE(FEDERATED_IDENTITY_API);
    TO_CEF_TYPE(NOTIFICATION_INTERACTIONS);
    TO_CEF_TYPE(REDUCED_ACCEPT_LANGUAGE);
    TO_CEF_TYPE(NOTIFICATION_PERMISSION_REVIEW);
    TO_CEF_TYPE(PRIVATE_NETWORK_GUARD);
    TO_CEF_TYPE(PRIVATE_NETWORK_CHOOSER_DATA);
    TO_CEF_TYPE(FEDERATED_IDENTITY_IDENTITY_PROVIDER_SIGNIN_STATUS);
    TO_CEF_TYPE(REVOKED_UNUSED_SITE_PERMISSIONS);
    TO_CEF_TYPE(TOP_LEVEL_STORAGE_ACCESS);
    TO_CEF_TYPE(FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION);
    TO_CEF_TYPE(FEDERATED_IDENTITY_IDENTITY_PROVIDER_REGISTRATION);
    TO_CEF_TYPE(ANTI_ABUSE);
    TO_CEF_TYPE(THIRD_PARTY_STORAGE_PARTITIONING);
    TO_CEF_TYPE(HTTPS_ENFORCED);
    TO_CEF_TYPE(ALL_SCREEN_CAPTURE);
    TO_CEF_TYPE(COOKIE_CONTROLS_METADATA);
    TO_CEF_TYPE(TPCD_HEURISTICS_GRANTS);
    TO_CEF_TYPE(TPCD_METADATA_GRANTS);
    TO_CEF_TYPE(TPCD_TRIAL);
    TO_CEF_TYPE(TOP_LEVEL_TPCD_TRIAL);
    TO_CEF_TYPE(TOP_LEVEL_TPCD_ORIGIN_TRIAL);
    TO_CEF_TYPE(AUTO_PICTURE_IN_PICTURE);
    TO_CEF_TYPE(FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION);
    TO_CEF_TYPE(FILE_SYSTEM_ACCESS_RESTORE_PERMISSION);
    TO_CEF_TYPE(CAPTURED_SURFACE_CONTROL);
    TO_CEF_TYPE(SMART_CARD_GUARD);
    TO_CEF_TYPE(SMART_CARD_DATA);
    TO_CEF_TYPE(WEB_PRINTING);
    TO_CEF_TYPE(AUTOMATIC_FULLSCREEN);
    TO_CEF_TYPE(SUB_APP_INSTALLATION_PROMPTS);
    TO_CEF_TYPE(SPEAKER_SELECTION);
    TO_CEF_TYPE(DIRECT_SOCKETS);
    TO_CEF_TYPE(KEYBOARD_LOCK);
    TO_CEF_TYPE(POINTER_LOCK);
    TO_CEF_TYPE(REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS);
    TO_CEF_TYPE(TRACKING_PROTECTION);
    TO_CEF_TYPE(DISPLAY_MEDIA_SYSTEM_AUDIO);
    TO_CEF_TYPE(JAVASCRIPT_OPTIMIZER);
    TO_CEF_TYPE(STORAGE_ACCESS_HEADER_ORIGIN_TRIAL);
    TO_CEF_TYPE(HAND_TRACKING);
    TO_CEF_TYPE(WEB_APP_INSTALLATION);
    TO_CEF_TYPE(DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS);
    TO_CEF_TYPE(LEGACY_COOKIE_SCOPE);
    TO_CEF_TYPE(ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER);
    TO_CEF_TYPE(CONTROLLED_FRAME);
    TO_CEF_TYPE(REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS);
    TO_CEF_TYPE(LOCAL_NETWORK_ACCESS);
    TO_CEF_TYPE(ON_DEVICE_SPEECH_RECOGNITION_LANGUAGES_DOWNLOADED);
    TO_CEF_TYPE(INITIALIZED_TRANSLATIONS);
    TO_CEF_TYPE(SUSPICIOUS_NOTIFICATION_IDS);
    case ContentSettingsType::DEFAULT:
      break;
  }

  NOTREACHED();
}

#define FROM_CEF_TYPE(name)             \
  case CEF_CONTENT_SETTING_TYPE_##name: \
    return ContentSettingsType::name

std::optional<ContentSettingsType> FromCefType(
    cef_content_setting_types_t type) {
  switch (type) {
    FROM_CEF_TYPE(COOKIES);
    FROM_CEF_TYPE(IMAGES);
    FROM_CEF_TYPE(JAVASCRIPT);
    FROM_CEF_TYPE(POPUPS);
    FROM_CEF_TYPE(GEOLOCATION);
    FROM_CEF_TYPE(NOTIFICATIONS);
    FROM_CEF_TYPE(AUTO_SELECT_CERTIFICATE);
    FROM_CEF_TYPE(MIXEDSCRIPT);
    FROM_CEF_TYPE(MEDIASTREAM_MIC);
    FROM_CEF_TYPE(MEDIASTREAM_CAMERA);
    FROM_CEF_TYPE(PROTOCOL_HANDLERS);
    FROM_CEF_TYPE(DEPRECATED_PPAPI_BROKER);
    FROM_CEF_TYPE(AUTOMATIC_DOWNLOADS);
    FROM_CEF_TYPE(MIDI_SYSEX);
    FROM_CEF_TYPE(SSL_CERT_DECISIONS);
    FROM_CEF_TYPE(PROTECTED_MEDIA_IDENTIFIER);
    FROM_CEF_TYPE(APP_BANNER);
    FROM_CEF_TYPE(SITE_ENGAGEMENT);
    FROM_CEF_TYPE(DURABLE_STORAGE);
    FROM_CEF_TYPE(USB_CHOOSER_DATA);
    FROM_CEF_TYPE(BLUETOOTH_GUARD);
    FROM_CEF_TYPE(BACKGROUND_SYNC);
    FROM_CEF_TYPE(AUTOPLAY);
    FROM_CEF_TYPE(IMPORTANT_SITE_INFO);
    FROM_CEF_TYPE(PERMISSION_AUTOBLOCKER_DATA);
    FROM_CEF_TYPE(ADS);
    FROM_CEF_TYPE(ADS_DATA);
    FROM_CEF_TYPE(MIDI);
    FROM_CEF_TYPE(PASSWORD_PROTECTION);
    FROM_CEF_TYPE(MEDIA_ENGAGEMENT);
    FROM_CEF_TYPE(SOUND);
    FROM_CEF_TYPE(CLIENT_HINTS);
    FROM_CEF_TYPE(SENSORS);
    FROM_CEF_TYPE(DEPRECATED_ACCESSIBILITY_EVENTS);
    FROM_CEF_TYPE(PAYMENT_HANDLER);
    FROM_CEF_TYPE(USB_GUARD);
    FROM_CEF_TYPE(BACKGROUND_FETCH);
    FROM_CEF_TYPE(INTENT_PICKER_DISPLAY);
    FROM_CEF_TYPE(IDLE_DETECTION);
    FROM_CEF_TYPE(SERIAL_GUARD);
    FROM_CEF_TYPE(SERIAL_CHOOSER_DATA);
    FROM_CEF_TYPE(PERIODIC_BACKGROUND_SYNC);
    FROM_CEF_TYPE(BLUETOOTH_SCANNING);
    FROM_CEF_TYPE(HID_GUARD);
    FROM_CEF_TYPE(HID_CHOOSER_DATA);
    FROM_CEF_TYPE(WAKE_LOCK_SCREEN);
    FROM_CEF_TYPE(WAKE_LOCK_SYSTEM);
    FROM_CEF_TYPE(LEGACY_COOKIE_ACCESS);
    FROM_CEF_TYPE(FILE_SYSTEM_WRITE_GUARD);
    FROM_CEF_TYPE(NFC);
    FROM_CEF_TYPE(BLUETOOTH_CHOOSER_DATA);
    FROM_CEF_TYPE(CLIPBOARD_READ_WRITE);
    FROM_CEF_TYPE(CLIPBOARD_SANITIZED_WRITE);
    FROM_CEF_TYPE(SAFE_BROWSING_URL_CHECK_DATA);
    FROM_CEF_TYPE(VR);
    FROM_CEF_TYPE(AR);
    FROM_CEF_TYPE(FILE_SYSTEM_READ_GUARD);
    FROM_CEF_TYPE(STORAGE_ACCESS);
    FROM_CEF_TYPE(CAMERA_PAN_TILT_ZOOM);
    FROM_CEF_TYPE(WINDOW_MANAGEMENT);
    FROM_CEF_TYPE(LOCAL_FONTS);
    FROM_CEF_TYPE(PERMISSION_AUTOREVOCATION_DATA);
    FROM_CEF_TYPE(FILE_SYSTEM_LAST_PICKED_DIRECTORY);
    FROM_CEF_TYPE(DISPLAY_CAPTURE);
    FROM_CEF_TYPE(FILE_SYSTEM_ACCESS_CHOOSER_DATA);
    FROM_CEF_TYPE(FEDERATED_IDENTITY_SHARING);
    FROM_CEF_TYPE(JAVASCRIPT_JIT);
    FROM_CEF_TYPE(HTTP_ALLOWED);
    FROM_CEF_TYPE(FORMFILL_METADATA);
    FROM_CEF_TYPE(DEPRECATED_FEDERATED_IDENTITY_ACTIVE_SESSION);
    FROM_CEF_TYPE(AUTO_DARK_WEB_CONTENT);
    FROM_CEF_TYPE(REQUEST_DESKTOP_SITE);
    FROM_CEF_TYPE(FEDERATED_IDENTITY_API);
    FROM_CEF_TYPE(NOTIFICATION_INTERACTIONS);
    FROM_CEF_TYPE(REDUCED_ACCEPT_LANGUAGE);
    FROM_CEF_TYPE(NOTIFICATION_PERMISSION_REVIEW);
    FROM_CEF_TYPE(PRIVATE_NETWORK_GUARD);
    FROM_CEF_TYPE(PRIVATE_NETWORK_CHOOSER_DATA);
    FROM_CEF_TYPE(FEDERATED_IDENTITY_IDENTITY_PROVIDER_SIGNIN_STATUS);
    FROM_CEF_TYPE(REVOKED_UNUSED_SITE_PERMISSIONS);
    FROM_CEF_TYPE(TOP_LEVEL_STORAGE_ACCESS);
    FROM_CEF_TYPE(FEDERATED_IDENTITY_AUTO_REAUTHN_PERMISSION);
    FROM_CEF_TYPE(FEDERATED_IDENTITY_IDENTITY_PROVIDER_REGISTRATION);
    FROM_CEF_TYPE(ANTI_ABUSE);
    FROM_CEF_TYPE(THIRD_PARTY_STORAGE_PARTITIONING);
    FROM_CEF_TYPE(HTTPS_ENFORCED);
    FROM_CEF_TYPE(ALL_SCREEN_CAPTURE);
    FROM_CEF_TYPE(COOKIE_CONTROLS_METADATA);
    FROM_CEF_TYPE(TPCD_HEURISTICS_GRANTS);
    FROM_CEF_TYPE(TPCD_METADATA_GRANTS);
    FROM_CEF_TYPE(TPCD_TRIAL);
    FROM_CEF_TYPE(TOP_LEVEL_TPCD_TRIAL);
    FROM_CEF_TYPE(TOP_LEVEL_TPCD_ORIGIN_TRIAL);
    FROM_CEF_TYPE(AUTO_PICTURE_IN_PICTURE);
    FROM_CEF_TYPE(FILE_SYSTEM_ACCESS_EXTENDED_PERMISSION);
    FROM_CEF_TYPE(FILE_SYSTEM_ACCESS_RESTORE_PERMISSION);
    FROM_CEF_TYPE(CAPTURED_SURFACE_CONTROL);
    FROM_CEF_TYPE(SMART_CARD_GUARD);
    FROM_CEF_TYPE(SMART_CARD_DATA);
    FROM_CEF_TYPE(WEB_PRINTING);
    FROM_CEF_TYPE(AUTOMATIC_FULLSCREEN);
    FROM_CEF_TYPE(SUB_APP_INSTALLATION_PROMPTS);
    FROM_CEF_TYPE(SPEAKER_SELECTION);
    FROM_CEF_TYPE(DIRECT_SOCKETS);
    FROM_CEF_TYPE(KEYBOARD_LOCK);
    FROM_CEF_TYPE(POINTER_LOCK);
    FROM_CEF_TYPE(REVOKED_ABUSIVE_NOTIFICATION_PERMISSIONS);
    FROM_CEF_TYPE(TRACKING_PROTECTION);
    FROM_CEF_TYPE(DISPLAY_MEDIA_SYSTEM_AUDIO);
    FROM_CEF_TYPE(JAVASCRIPT_OPTIMIZER);
    FROM_CEF_TYPE(STORAGE_ACCESS_HEADER_ORIGIN_TRIAL);
    FROM_CEF_TYPE(HAND_TRACKING);
    FROM_CEF_TYPE(WEB_APP_INSTALLATION);
    FROM_CEF_TYPE(DIRECT_SOCKETS_PRIVATE_NETWORK_ACCESS);
    FROM_CEF_TYPE(LEGACY_COOKIE_SCOPE);
    FROM_CEF_TYPE(ARE_SUSPICIOUS_NOTIFICATIONS_ALLOWLISTED_BY_USER);
    FROM_CEF_TYPE(CONTROLLED_FRAME);
    FROM_CEF_TYPE(REVOKED_DISRUPTIVE_NOTIFICATION_PERMISSIONS);
    FROM_CEF_TYPE(LOCAL_NETWORK_ACCESS);
    FROM_CEF_TYPE(ON_DEVICE_SPEECH_RECOGNITION_LANGUAGES_DOWNLOADED);
    FROM_CEF_TYPE(INITIALIZED_TRANSLATIONS);
    FROM_CEF_TYPE(SUSPICIOUS_NOTIFICATION_IDS);
    case CEF_CONTENT_SETTING_TYPE_INSECURE_PRIVATE_NETWORK_DEPRECATED:
    case CEF_CONTENT_SETTING_TYPE_NUM_VALUES:
      break;
  }

  return std::nullopt;
}

}  // namespace setting_helper
